"""
GT-LMS system data persistence implementation
This module provides JSON file read/write functionality for data persistence
"""

import json
import os
import shutil
from datetime import datetime
from typing import Any, Dict, List, Optional
from pathlib import Path

class DataPersistence:
    """Data persistence class - Bonus feature"""

    def __init__(self, data_dir: str = None, backup_dir: str = None):
        """
        Initialize data persistence class

        Parameters:
            data_dir (str): Data directory path, if None use path relative to module
            backup_dir (str): Backup directory path, if None use path relative to module
        """
        # Get current module directory
        current_module_dir = Path(__file__).parent.parent
        
        # Set data directory - prioritize passed parameter, otherwise use module-relative data directory
        if data_dir is None:
            self.data_dir = current_module_dir / "data"
        else:
            self.data_dir = Path(data_dir)
            
        # Set backup directory - prioritize passed parameter, otherwise use module-relative backups directory
        if backup_dir is None:
            self.backup_dir = current_module_dir / "backups"
        else:
            self.backup_dir = Path(backup_dir)

        # Create directories if they don't exist
        self.data_dir.mkdir(exist_ok=True)
        self.backup_dir.mkdir(exist_ok=True)

    def save_users(self, users: Dict) -> bool:
        """
        Save user data to JSON file

        Parameters:
            users (Dict): User data dictionary

        Returns:
            bool: Returns True if save successful, False otherwise
        """
        try:
            file_path = self.data_dir / "users.json"
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(users, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error saving user data: {e}")
            return False

    def load_users(self) -> Dict:
        """
        Load user data from JSON file

        Returns:
            Dict: User data dictionary
        """
        try:
            file_path = self.data_dir / "users.json"
            if not file_path.exists():
                return {}

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error loading user data: {e}")
            return {}

    def save_courses(self, courses: Dict) -> bool:
        """
        Save course data to JSON file

        Parameters:
            courses (Dict): Course data dictionary

        Returns:
            bool: Returns True if save successful, False otherwise
        """
        try:
            file_path = self.data_dir / "courses.json"
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(courses, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error saving course data: {e}")
            return False

    def load_courses(self) -> Dict:
        """
        Load course data from JSON file

        Returns:
            Dict: Course data dictionary
        """
        try:
            file_path = self.data_dir / "courses.json"
            if not file_path.exists():
                return {}

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error loading course data: {e}")
            return {}

    def save_enrollments(self, enrollments: Dict) -> bool:
        """
        Save enrollment data to JSON file

        Parameters:
            enrollments (Dict): Enrollment data dictionary

        Returns:
            bool: Returns True if save successful, False otherwise
        """
        try:
            file_path = self.data_dir / "enrollments.json"
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(enrollments, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error saving enrollment data: {e}")
            return False

    def load_enrollments(self) -> Dict:
        """
        Load enrollment data from JSON file

        Returns:
            Dict: Enrollment data dictionary
        """
        try:
            file_path = self.data_dir / "enrollments.json"
            if not file_path.exists():
                return {}

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error loading enrollment data: {e}")
            return {}

    def save_assignments(self, assignments: Dict) -> bool:
        """
        Save assignment data to JSON file

        Parameters:
            assignments (Dict): Assignment data dictionary

        Returns:
            bool: Returns True if save successful, False otherwise
        """
        try:
            file_path = self.data_dir / "assignments.json"
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(assignments, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error saving assignment data: {e}")
            return False

    def load_assignments(self) -> Dict:
        """
        Load assignment data from JSON file

        Returns:
            Dict: Assignment data dictionary
        """
        try:
            file_path = self.data_dir / "assignments.json"
            if not file_path.exists():
                return {}

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error loading assignment data: {e}")
            return {}

    def save_submissions(self, submissions: Dict) -> bool:
        """
        Save submission data to JSON file

        Parameters:
            submissions (Dict): Submission data dictionary

        Returns:
            bool: Returns True if save successful, False otherwise
        """
        try:
            file_path = self.data_dir / "submissions.json"
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(submissions, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error saving submission data: {e}")
            return False

    def load_submissions(self) -> Dict:
        """
        Load submission data from JSON file

        Returns:
            Dict: Submission data dictionary
        """
        try:
            file_path = self.data_dir / "submissions.json"
            if not file_path.exists():
                return {}

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error loading submission data: {e}")
            return {}

    def save_grades(self, grades: Dict) -> bool:
        """
        Save grade data to JSON file

        Parameters:
            grades (Dict): Grade data dictionary

        Returns:
            bool: Returns True if save successful, False otherwise
        """
        try:
            file_path = self.data_dir / "grades.json"
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(grades, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error saving grade data: {e}")
            return False

    def load_grades(self) -> Dict:
        """
        Load grade data from JSON file

        Returns:
            Dict: Grade data dictionary
        """
        try:
            file_path = self.data_dir / "grades.json"
            if not file_path.exists():
                return {}

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error loading grade data: {e}")
            return {}

    def backup_all(self) -> bool:
        """
        Backup all data

        Returns:
            bool: Returns True if backup successful, False otherwise
        """
        try:
            # Create backup directory with timestamp
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            backup_path = self.backup_dir / f"backup_{timestamp}"
            backup_path.mkdir(exist_ok=True)

            # Copy all data files to backup directory
            for file_path in self.data_dir.glob("*.json"):
                if file_path.exists():
                    shutil.copy2(file_path, backup_path)

            return True
        except Exception as e:
            print(f"Error backing up data: {e}")
            return False

    def restore_from_backup(self, backup_name: str) -> bool:
        """
        Restore data from backup

        Parameters:
            backup_name (str): Backup directory name

        Returns:
            bool: Returns True if restore successful, False otherwise
        """
        try:
            backup_path = self.backup_dir / backup_name
            if not backup_path.exists():
                print(f"Backup directory {backup_name} does not exist")
                return False

            # Copy backup files to data directory
            for file_path in backup_path.glob("*.json"):
                if file_path.exists():
                    shutil.copy2(file_path, self.data_dir)

            return True
        except Exception as e:
            print(f"Error restoring data from backup: {e}")
            return False

    def export_to_json(self, data: Any, filename: str) -> bool:
        """
        Export data to JSON file

        Parameters:
            data (Any): Data to export
            filename (str): Export filename

        Returns:
            bool: Returns True if export successful, False otherwise
        """
        try:
            file_path = self.data_dir / filename
            with open(file_path, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
            return True
        except Exception as e:
            print(f"Error exporting data: {e}")
            return False

    def import_from_json(self, filename: str) -> Any:
        """
        Import data from JSON file

        Parameters:
            filename (str): Filename to import

        Returns:
            Any: Imported data
        """
        try:
            file_path = self.data_dir / filename
            if not file_path.exists():
                print(f"File {filename} does not exist")
                return None

            with open(file_path, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Error importing data: {e}")
            return None

    def list_backups(self) -> List[str]:
        """
        List all backups

        Returns:
            List[str]: List of backup directory names
        """
        try:
            backups = []
            for item in self.backup_dir.iterdir():
                if item.is_dir():
                    backups.append(item.name)
            return sorted(backups, reverse=True)  # Sort in reverse chronological order
        except Exception as e:
            print(f"Error listing backups: {e}")
            return []

    def delete_backup(self, backup_name: str) -> bool:
        """
        Delete specified backup

        Parameters:
            backup_name (str): Name of backup to delete

        Returns:
            bool: Returns True if deletion successful, False otherwise
        """
        try:
            backup_path = self.backup_dir / backup_name
            if not backup_path.exists():
                print(f"Backup {backup_name} does not exist")
            return False

            shutil.rmtree(backup_path)
            return True
        except Exception as e:
            print(f"Error deleting backup: {e}")
            return False

    def validate_data(self, data: Dict, data_type: str) -> bool:
        """
        Validate data format

        Parameters:
            data (Dict): Data to validate
            data_type (str): Data type ('user', 'course', 'submission', 'grade')

        Returns:
            bool: Returns True if data format is correct, False otherwise
        """
        if not isinstance(data, dict):
            return False

        # Check if data contains required fields
        # More detailed validation can be added based on specific data types

        return True

    def get_data_file_path(self, data_type: str) -> Path:
        """
        Get data file path

        Parameters:
            data_type (str): Data type

        Returns:
            Path: Data file path
        """
        return self.data_dir / f"{data_type}.json"

    def data_exists(self, data_type: str) -> bool:
        """
        Check if data file exists

        Parameters:
            data_type (str): Data type

        Returns:
            bool: Returns True if file exists, False otherwise
        """
        return self.get_data_file_path(data_type).exists()

    def get_backup_info(self, backup_name: str) -> Optional[Dict]:
        """
        Get backup information

        Parameters:
            backup_name (str): Backup name

        Returns:
            Optional[Dict]: Backup information dictionary, returns None if backup doesn't exist
        """
        backup_path = self.backup_dir / backup_name
        if not backup_path.exists():
            return None

        try:
            stat = backup_path.stat()
            return {
                'name': backup_name,
                'created': datetime.fromtimestamp(stat.st_mtime),
                'size': stat.st_size
            }
        except Exception as e:
            print(f"Error getting backup information: {e}")
            return None

    def cleanup_old_backups(self, days: int = 30) -> int:
        """
        Clean up old backups

        Parameters:
            days (int): Retention days

        Returns:
            int: Number of backups deleted
        """
        try:
            cutoff_time = datetime.now() - timedelta(days=days)
            deleted_count = 0

            for backup_dir in self.backup_dir.iterdir():
                if backup_dir.is_dir():
                    stat = backup_dir.stat()
                    if datetime.fromtimestamp(stat.st_mtime) < cutoff_time:
                        shutil.rmtree(backup_dir)
                        deleted_count += 1

            return deleted_count
        except Exception as e:
            print(f"Error cleaning up old backups: {e}")
            return 0